#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <ucontext.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/mman.h>

#include "map_utils_linux.h"

//------------------------------------------------------------------------------

TBGError ConvertMapFile(size_t inputc, const char **inputv,
                        const char *output) {
    TBGError ret = 0;
    CHECK_DBG_ERR(inputv, NULL_PTR);
    CHECK_DBG_ERR(inputc, ZERO_LENGTH);
    CHECK_DBG_ERR(output, INVALID_FILE);
    char buffer[1000] = {0};
    int i = 0;
    for(i = 0; i < inputc; ++i) {
        CHECK_DBG_ERR(inputv[i], INVALID_FILE);
        sprintf(buffer, "./process_map.sed %400s %400s", inputv[i], output);
        CHECK_RET(system(buffer) != -1, SYSTEM_CALL_FAILED, exit_point, ret);
    }

exit_point:
    return ret;
}

//------------------------------------------------------------------------------

TBGError _ScanMapFile(func_map *pmap, const char *file) {
    TBGError ret = 0;
    CHECK_DBG_ERR(pmap, NULL_PTR);
    CHECK_DBG_ERR(file, NULL_PTR);
    CHECK_DBG_ERR(pmap->size_, ZERO_LENGTH);
    CHECK_DBG_ERR(pmap->map_, NULL_PTR);
    CHECK_DBG_ERR(pmap->names_, NULL_PTR);

    int fd = 0;
    struct stat sb;
    char *map = NULL;  /*mmapped array of int's */

    fd = open(file, O_RDONLY);
    CHECK_RET(fd != -1, CANNOT_OPEN_FILE_R, exit_point, ret);

    map = mmap(0, sb.st_size, PROT_READ, MAP_SHARED, fd, 0);
    CHECK_RET(map != MAP_FAILED, CANNOT_MMAP_FILE, close_point, ret);
    //start using file here
     
    pmap->size_ /*approximately*/ = sb.st_size / 16;
    pmap->map_ = malloc(pmap->size_ * sizeof(func_map_info));
    pmap->names_ = malloc(pmap->size_ * sizeof(name_t));
    CHECK_RET(pmap->map_, CANNOT_ALLOC_MEMORY, free_point, ret);
    CHECK_RET(pmap->names_, CANNOT_ALLOC_MEMORY, free_point, ret);

    unsigned int read = 0;
    unsigned int i = 0, map_i = 0;
    for(i = 0, map_i = 0; i < sb.st_size; ++i, ++map_i) {
        sscanf(map + i, "%x %127[^\n]%n",
               (unsigned int*)&(pmap->map_[map_i].addr_),
               pmap->names_[map_i], (unsigned int*)&read);
        pmap->map_[map_i].name_idx_ = map_i;
        i += read;

/*       printf("i = %d, map_i = %d, tmp = [%s] addr = %x,
                name = [%s]\n", i, map_i, tmp, 
                pmap->memory_map_[map_i].addr_,
                pmap->memory_map_[map_i].name_);
*/
        if(map_i >= pmap->size_) {
            pmap->size_ *= 2;
            pmap->map_ = realloc(pmap->map_,
                                 pmap->size_ * sizeof(func_map_info));
            CHECK_RET(pmap->map_, CANNOT_ALLOC_MEMORY, free_point, ret);

            pmap->names_ = realloc(pmap->names_, pmap->size_ * sizeof(name_t));
            CHECK_RET(pmap->names_, CANNOT_ALLOC_MEMORY, free_point, ret);
        }
    }
    pmap->size_ = map_i;

free_point:
    free(pmap->map_);
    free(pmap->names_);

    CHECK_RET(munmap(map, sb.st_size) != -1, CANNOT_UNMAP_FILE,
              close_point, ret);
close_point:
    close(fd);
exit_point:
    return ret;
}

